/*
 * spi.h
 *
 *  Created on: Sep 30, 2013
 *      Author: Ken Arok
 */

#ifndef SPI_H_
#define SPI_H_

#include "config_board.h"

#if BOARD_2_1_USED


#define CONFIG_SPI_MASTER		1
#define CONFIG_SPI_SLAVE		2

#define CONFIG_SPI_MODE0		0
#define CONFIG_SPI_MODE1		1
#define CONFIG_SPI_MODE2		2
#define CONFIG_SPI_MODE3		3

#define CONFIG_ORDER_MSB_FIRST	1
#define CONFIG_ORDER_LSB_FIRST	2


//! Enumeration of serial port name.
typedef enum {
	serSPI1 = 0,
	serSPI2,
	serSPI3
}SPI_port_t;


//! Status codes used by the SPI driver.
typedef enum {
	SPI_STATUS_OK				=  0, //!< Success
	SPI_ERR_IO_ERROR			=  -1, //!< I/O error
	SPI_ERR_FLUSHED				=  -2, //!< Request flushed from queue
	SPI_ERR_TIMEOUT				=  -3, //!< Operation timed out
	SPI_ERR_BAD_DATA			=  -4, //!< Data integrity check failed
	SPI_ERR_PROTOCOL			=  -5, //!< Protocol error
	SPI_ERR_UNSUPPORTED_DEV		=  -6, //!< Unsupported device
	SPI_ERR_NO_MEMORY			=  -7, //!< Insufficient memory
	SPI_ERR_INVALID_ARG			=  -8, //!< Invalid argument
	SPI_ERR_BAD_ADDRESS			=  -9, //!< Bad address
	SPI_ERR_BUSY				=  -10, //!< Resource is busy
	SPI_ERR_BAD_FORMAT			=  -11, //!< Data format not recognized
	SPI_OPERATION_IN_PROGRESS	= -128,
} spi_status_code_t;


typedef enum {
	SPI_POLLED = 0,
	SPI_INTERRUPT
} spi_transfer_mode_flag_t;


typedef struct {
	uint8_t master;			//! Master or Slave
	uint8_t mode;			//! SPI Mode: 0, 1, 2, 3
	uint8_t transfer_order;	//! MSB first or LSB First
} spi_options_t;

/* Global signaling to wake up higher task. */
extern volatile bool xSPISignaling;


/** \brief Initialize SPI as Master.
 *
 */
extern void spi_master_init(void);

/** \brief Initialize SPI as Slave.
 *
 */
extern void spi_slave_init(void);


/** \brief Open the SPI port.
 *
 * \param _xPort	The port communication want to be used.
 * \param _flag		Flag of opening.
 *
 * \return Status.
 *	\retval	SPI_STATUS_OK		Port is ready.
 *	\retval SPI_ERR_TIMEOUT	Port is not ready.
 *
 */
extern spi_status_code_t spi_open(SPI_port_t _xPort, const uint8_t _flag);


/** \brief Close the SPI port.
 *
 * \param _xPort		The port communication want to be used.
 *
 */
extern void spi_close(SPI_port_t _xPort);

/** \brief Send a packet of byte data out to SPI serial port.
 *
 * \param _xPort		The port SPI.
 * \param _pPacket		Pointer to the packet data want to be sent out.
 * \param _size_t		The length of packet want to be sent out.
 *
 * \return Status
 *	\retval SPI_STATUS_OK		Success, data is being written.
 *	\retval SPI_INVALID_ARG		Failed due to invalid port COM.
 *  \retval SPI_ERR_TIMEOUT		Transmission timeout.
 */
extern spi_status_code_t spi_write_byte(SPI_port_t _xPort, const void *_pPacket, uint32_t _size_t);

/** \brief Get a packet of byte data from serial port.
 *
 * \param _xPort			The port SPI.
 * \param _pRxBuff			Pointer to the buffer where the packet data will be stored.
 * \param _size_t			Number of byte of data must be received.
 * \param _pRcvdSize		Pointer to the variable counting received data.
 *
 * \return Status
 *	\retval SPI_STATUS_OK		Success, start capturing data.
 *	\retval SPI_INVALID_ARG	Failed due to invalid port COM.
 *
 */
extern spi_status_code_t spi_read_byte(SPI_port_t _xPort, void *_pRxBuff, uint32_t _size_t, uint32_t *_pRcvdSize);


/** \brief Setting up SPI communication.
 *
 * \param _xPort	The port COM.
 * \param _opt		SPI option parameter.
 *
 */
extern void spi_setup(SPI_port_t _xPort, const spi_options_t *_opt);

/** \brief Set SPI transfer mode.
 *
 * \param _xPort	The port COM.
 * \param _flag		Mode flag.
 *					SPI_POLLED: TX & RX = Polled.
 *					SPI_INTERRUPT: TX & RX = Interrupt.
 *
 */
extern void spi_tranfer_mode(SPI_port_t _xPort, spi_transfer_mode_flag_t _flag);


/** \brief Set timeout value to receiver.
 *
 * \param _xPort	The port.
 * \param _to_ms	Timeout value in milisecond (10 ms unit).
 *
 */
extern void spi_rx_timeout(SPI_port_t _xPort, const uint32_t _to_ms);


#endif /* BOARD_2_1_USED */

#endif /* SPI_H_ */
